namespace pengpeng 
{
	export class DataParser 
    {
        constructor()
        {
            
        }

        protected static _getBoolean(rawData: any, key: string, defaultValue: boolean = false): boolean {
            if (key in rawData) {
                const value = rawData[key];
                const valueType = typeof value;
                if (valueType === "boolean") {
                    return value;
                }
                else if (valueType === "string") {
                    switch (value) {
                        case "0":
                        case "NaN":
                        case "":
                        case "false":
                        case "null":
                        case "undefined":
                            return false;

                        default:
                            return true;
                    }
                }
                else {
                    return !!value;
                }
            }

            return defaultValue;
        }
        /**
         * @private
         */
        protected static _getNumber(rawData: any, key: string, defaultValue: number = 0.0): number {
            if (key in rawData) {
                const value = rawData[key];
                if (value == null || value === "NaN") {
                    return defaultValue;
                }

                return +value || 0;
            }

            return defaultValue;
        }
        /**
         * @private
         */
        protected static _getString(rawData: any, key: string, defaultValue: string=""): string {
            if (key in rawData) {
                return String(rawData[key]);
            }

            return defaultValue;
        }

        public parse(raw:any):PPData
        {
            var ppData:PPData = new PPData();
            ppData.version = DataParser._getString(raw,"version");
            let i:number;
            let len:number;

            if(raw.materials)
            {
                ppData.materials = new Map<string,MaterialData>();

                for(i = 0, len = raw.materials.length; i < len; i++)
                {
                    var material:MaterialData = this.parseMaterial(raw.materials[i]);
                    if(material)
                    {
                        ppData.materials[material.name] = material;
                    }
                }
            }
            if(raw.shapes)
            {
                ppData.shapes = new Map<string,ShapeData>();

                for(i = 0, len = raw.shapes.length; i < len; i++)
                {
                    var shape:ShapeData = this.parseShape(raw.shapes[i]);
                    if(shape)
                    {
                        ppData.shapes[shape.name] = shape;
                    }
                }
            }
            if(raw.assets)
            {
                ppData.assets = new Map<string, AssetData>();

                for(i = 0, len = raw.assets.length; i < len; i++)
                {
                    var asset:AssetData = this.parseAsset(raw.assets[i]);
                    if(asset)
                    {
                        ppData.assets[asset.name] = asset;
                    }
                }
            }
            if(raw.world)
            {
                ppData.worlds = new Map<string,WorldData>();

               var worldData:WorldData = this.parseWorld(raw.world, ppData);
               ppData.worlds[worldData.name] = worldData;
            }
            return ppData;
        }

        public parseMaterial(raw:any):MaterialData
        {
            var f = this.parseObj<MaterialData>(MaterialData,raw);
            return f;
        }

        public parseShape(raw:any):ShapeData
        {
            var f = this.parseObj<ShapeData>(ShapeData,raw);
            return f;
        }

        public parseAsset(raw:any):AssetData
        {
            var f = this.parseObj<AssetData>(AssetData,raw);
            return f;
        }
        public parseWorld(raw:any, ppData:PPData):WorldData
        {
            let w:WorldData = new WorldData();
            let i:number;
            let len:number;
            w.name = DataParser._getString(raw,"name");
            w.positionIterations = DataParser._getNumber(raw,"positionIterations");
            w.velocityIterations = DataParser._getNumber(raw,"velocityIterations");
            w.gravity = new Point(raw.gravity[0],raw.gravity[1]);
            if(raw.bodies)
            {
                for(i = 0,len = raw.bodies.length; i < len; i++)
                {
                    let b:BodyData = this.parseBody(raw.bodies[i],ppData);
                    if(b){
                        w.bodies.push(b);                        
                    }
                }
            }
            if(raw.joints)
            {
                for(i = 0,len = raw.joints.length; i < len; i++)
                {
                    let j:JointData = this.parseJoint(raw.joints[i],ppData);
                    if(j){
                        w.joints.push(j);                        
                    }
                }
            }
            return w;
        }

        public parseBody(raw:any,ppData:PPData):BodyData
        {
            var f = this.parseObj<BodyData>(BodyData,raw);
            f.assetData = ppData.assets[f.asset];
            f.materialData = ppData.materials[f.material];
            f.shapeData = ppData.shapes[f.shape];
            return f;
        }
        public parseJoint(raw:any,ppData:PPData):JointData
        {
            var f = this.parseObj<JointData>(JointData,raw);
            return f;
        }

        private parseObj<T>(c: {new(): T; },raw:any):T
        {
            var m:T = new c();
            for( let p in raw)
            {
                if(typeof(raw[p]) =="object" && raw[p].length == 2)
                {
                    m[p] = new Point(raw[p][0],raw[p][1]);
                }
                else
                {
                    m[p] = raw[p];
                }  
            }
            return m;
        }
    }
}